/* Projet LO43 A11 */
#include <stdio.h>
#include <pthread.h>

#define NbTh 2     //Nombre de processus symbolisant les trains

pthread_t tid[NbTh+1];
//pthread_mutex_t mutex;

//Aig2
pthread_cond_t trainAttAig2, aig2Libre;
pthread_mutex_t mutexAig2;
int NbTrainsAttenteAig2=0;

//Tunnel
pthread_cond_t trainAttTunnel, tunnelLibre;
pthread_mutex_t mutexTunnel;
int NbTrainsAttenteTunnel=0;

void aig2 (){
	pthread_mutex_lock(&mutexAig2);
	if(NbTrainsAttenteAig2>0){
		pthread_cond_signal(&trainAttAig2);		
	}else{             
                pthread_cond_wait(&aig2Libre, &mutexAig2);  
		pthread_cond_signal(&trainAttAig2);
	}
	pthread_mutex_unlock(&mutexAig2);
}

void passageAig2(int i){
	pthread_mutex_lock(&mutexAig2);
	NbTrainsAttenteAig2++;
	pthread_cond_signal(&aig2Libre);
	printf("Train %d avertit aig2 qu'il souhaite passer\n",i);
	pthread_cond_wait(&trainAttAig2,&mutexAig2);
	NbTrainsAttenteAig2--;
	printf("Train %d entre dans aig2\n",(int)i);
	sleep(5);
	printf("Train %d quitte dans aig2\n",(int)i);
	pthread_mutex_unlock(&mutexAig2);
}
void * fonc_aig2(){                          
	while(1){
		aig2();
		sleep(5);
	}
}
void tunnel (){
	pthread_mutex_lock(&mutexTunnel);
	if(NbTrainsAttenteTunnel>0){
		pthread_cond_signal(&trainAttTunnel);		
	}else{             
                pthread_cond_wait(&tunnelLibre, &mutexTunnel);  
		pthread_cond_signal(&trainAttTunnel);               
	}
	pthread_mutex_unlock(&mutexTunnel);
}

void passageTunnel(int i){
	pthread_mutex_lock(&mutexTunnel);
	NbTrainsAttenteTunnel++;
	pthread_cond_signal(&tunnelLibre);
	printf("Train %d avertit le tunnel qu'il souhaite passer\n",i);
	pthread_cond_wait(&trainAttTunnel,&mutexTunnel);
	NbTrainsAttenteTunnel--;
	printf("Train %d entre dans le tunnel\n",(int)i);
	sleep(5);
	printf("Train %d quitte le tunnel\n",(int)i);
	pthread_mutex_unlock(&mutexTunnel);
}
void * fonc_tunnel(){                          
	while(1){
		tunnel();
		sleep(5);
	}
}

void * fonc_train_OE(void *i){
	printf("Train %d arrive en gare \n",i);
	sleep(2);	
	printf("Train %d quitte la gare \n",i);
	passageAig2((int)i);
	printf("Train %d entre les voies de garages\n",(int)i);
	passageTunnel((int)i);
	printf("Train %d arrive sur la ligne\n",i);
}

void * fonc_train_EO(void *i){
	printf("Train %d arrive sur la ligne\n",i);
	passageTunnel((int)i);	
	printf("Train %d entre les voies de garages\n",i);
	sleep(2);
	printf("Train %d quitte les voies de garages\n",i);
	passageAig2((int)i);
	printf("Train %d entre en gare\n",(int)i);
}

int main(){
	int num;

	pthread_mutex_init(&mutexAig2,0);
	pthread_cond_init(&aig2Libre,0);
	pthread_cond_init(&trainAttAig2,0);
	pthread_mutex_init(&mutexTunnel,0);
	pthread_cond_init(&tunnelLibre,0);
	pthread_cond_init(&trainAttTunnel,0);

	// creation de la thread aig2,aig1,tunnel
	pthread_create(tid+NbTh,0,(void *(*)())fonc_aig2,(void*)NbTh);
	pthread_create(tid+NbTh+1,0,(void *(*)())fonc_tunnel,(void*)NbTh);

	//creation des threads train
	for(num=0;num<NbTh;num ++)
	        if(num%2==0)
			pthread_create(tid+num,0,(void *(*)())fonc_train_OE,(void*)num);
		else
			pthread_create(tid+num,0,(void *(*)())fonc_train_EO,(void*)num);

	//attend la fin de toutes les threads clients
	for(num=0;num<NbTh;num ++)
	        pthread_join(tid[num],NULL);
        
	/* liberation des ressources");*/
	pthread_mutex_destroy(&mutexAig2);
	pthread_cond_destroy(&aig2Libre);
	pthread_cond_destroy(&trainAttAig2);
	pthread_mutex_destroy(&mutexTunnel);
	pthread_cond_destroy(&tunnelLibre);
	pthread_cond_destroy(&trainAttTunnel);    

	exit(0);
}
